using System;
using UnityEngine;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine.SceneManagement;
using Debug = UnityEngine.Debug;

namespace Scene.Scripts
{
    public partial class SceneBox
    {
        public static int MaxLoadEveryFrame { get; private set; } = 30;
        public static Vector3 ViewCenter => SceneViewCenter.CenterViewCenter;
        public class SceneViewCenter
        {
            private SceneLoadConfig.DetailLod[] _lods;
            private static Vector3 _viewCenter;
            private Bounds _test0, _test1, _test2;

            public static Vector3 CenterViewCenter
            {
                get => _viewCenter;
                set => _viewCenter = value;
            }
            
            private SceneViewCenter(){}

            public static SceneViewCenter View { get; private set; } = null;
            public static void OnInit(SceneLoadConfig.DetailLod[] lods)
            {
                View = new SceneViewCenter
                {
                    _lods = new SceneLoadConfig.DetailLod[lods.Length]
                };
                System.Array.Copy(lods, 0, View._lods, 0, lods.Length);
            }

            public int TestLodLevel(AssetDetailType detailType, SceneObj obj)
            {
                BeforeTest(detailType, obj);
                if (!SceneUtility.TestAABBOverlap(_test2,obj.objBounds))
                {
                    return -1;
                }
                if (!SceneUtility.TestAABBOverlap(_test1 ,obj.objBounds))
                {
                    return 2;
                }
                if (!SceneUtility.TestAABBOverlap(_test0 ,obj.objBounds))
                {
                    return 1;
                }
                return 0;
            }
            void BeforeTest(AssetDetailType detailType,SceneObj obj)
            {
                SceneLoadConfig.DetailLod lod = default;
                switch (detailType)
                {
                    case AssetDetailType.Important:
                        lod = _lods[0];
                        break;
                    case AssetDetailType.Detail1:
                        lod = _lods[1];
                        break;
                    case AssetDetailType.Detail2:
                        lod = _lods[2];
                        break;
                    case AssetDetailType.Detail3:
                        lod = _lods[3];
                        break;
                    case AssetDetailType.DynamicType:
                        lod = _lods[4];
                        break;
                    default:
                        throw new Exception("before test error");
                        break;
                }
                var r0 = lod.lod0Radius;
                var r1 = lod.lod1Radius;
                var r2 = lod.lod2Radius;
                _test0 = new Bounds(_viewCenter, Vector3.one * r0 * 2);
                _test1 = new Bounds(_viewCenter, Vector3.one * r1 * 2);
                _test2 = new Bounds(_viewCenter, Vector3.one * r2 * 2);
            }
        }

        public static int CurrentMaxLoadTimes { get; private set; } = 0;
        public static bool IsLoading { get; private set; } = false;
        public static float MinDynamicSpan { get; private set; }

        public static int CheckLodLevel(AssetDetailType detailType, SceneObj obj)
        {
            return SceneViewCenter.View.TestLodLevel(detailType, obj);
        }

        public static void DrawGlobalGizmos()
        {
            Gizmos.color = Color.white;
            foreach (var kvp in SceneManager.GameSceneBoxes)
            {
                var data = kvp.Value;
                var c = data.AnyLoadCount ? Color.blue : Color.white;
                Gizmos.color = c;
                Gizmos.DrawWireCube(data.BoxBounds.center, data.BoxBounds.size);
            }

            Gizmos.color = Color.red;
            foreach (var point in SceneManager.AllScenePoints)
            {
                Gizmos.DrawSphere(point.PointBound.center, 5);
            }
            
            Gizmos.color = Color.blue;
            Gizmos.DrawWireSphere(SceneBox.ViewCenter,1000);
        }

        public static void DrawViewGizmos(AssetDetailType detailType,float radius)
        {
            Gizmos.color = Color.white;
            foreach (var kvp in SceneManager.GameSceneBoxes)
            {
                var data = kvp.Value;
                if (data.GetAnyLoadCount(detailType))
                {
                    Gizmos.color = Color.blue;
                    Gizmos.DrawWireCube(data.BoxBounds.center, data.BoxBounds.size);   
                }
            }
            
            Gizmos.color = Color.yellow;
            Gizmos.DrawWireCube(SceneBox.ViewCenter,Vector3.one * radius);
        }

        public static void UpdateScene(Vector3 center, LoadRadius[] loadRadius)
        {
            SceneViewCenter.CenterViewCenter = center;
            
            SceneManager.RefreshScene(center, loadRadius);
            SceneObj.LoadFromScene(SceneManager.LoadChangeSemaphore);
        }

        public static System.Collections.IEnumerator LoadScene(SceneLoadConfig config, Vector3 center, LoadRadius[] loadRadius)
        {
            if (IsLoading)
                yield break;

            IsLoading = true;
            Application.runInBackground = true;
            
            if (string.IsNullOrEmpty(config.globalScene))
                throw new Exception("Load scene error, config error");
            if(config.allScenes == null || config.allScenes.Any(x => string.IsNullOrEmpty(x) == true))
                throw new Exception("Load scene error, config error");
            
            SceneBox.SceneViewCenter.OnInit(config.lods);
            UnityEngine.SceneManagement.SceneManager.LoadScene(config.globalScene, LoadSceneMode.Additive);
            yield return null;
            for (int i = 0; i < config.allScenes.Length; i++)
            {
                UnityEngine.SceneManagement.SceneManager.LoadScene(config.allScenes[i], LoadSceneMode.Additive);
            }

            yield return null;

            
            foreach (var item in loadRadius)
            {
                
            }
            
#if UNITY_EDITOR
            foreach (var kvp in SceneManager.GameSceneBoxes)
            {
                foreach (var item in kvp.Value.sceneObjMap)
                {
                    foreach (var obj in item.Value.Objs)
                    {
                        Debug.Log($"scene data info {kvp.Key},{item.Key},{obj.Name}");   
                    }
                }
            }
            Debug.Log($"scene manager info, all points = {SceneManager.AllScenePoints.Length},boxes = {SceneManager.GameSceneBoxes.Count}");
#endif
            
            yield return null;
            var tmp = MaxLoadEveryFrame;
            MaxLoadEveryFrame = int.MaxValue;
            UpdateScene(center, loadRadius);
            MaxLoadEveryFrame = tmp;
            yield return null;
        }

        public static void OnSceneQuit()
        {
            SceneObj.ReleaseRuntime();
        }
        internal static void OnSceneAssetLoaded(SceneAssets sceneAsset)
        {
            foreach (var item in sceneAsset.sceneDatas)
            {
                try
                {
                    SceneObj.IDynamicObj dynamicObj = null;
                    SceneObj obj = null;
                    if (item.assetType != AssetDetailType.DynamicType)
                    {
                        obj = item.sceneObj;
                    }
                    else
                    {
                        obj = item.dynamicObj;
                        if (item.dynamicObj.IsStatic == false)
                        {
                            SceneManager.AddDynamicObj(item.dynamicObj);
                            continue;
                        }
                    }

                    foreach (var boxId in item.sceneBoxIds)
                    {
                        var box = SceneManager.GameSceneBoxes[boxId];
                        var loading = box.sceneObjMap[item.assetType];

                        loading.Objs.Add(obj);
                        SceneUtility.LogInfo($"fill {item.assetType} obj {obj.Name} to SceneBox {boxId}");
                    }
                }
                catch (Exception e)
                {
                    Console.WriteLine(e);
                    throw;
                }
            }
        }

        internal static void OnGlobalAssetLoaded(GlobalAssets globalAsset)
        {
            SceneManager.Init(globalAsset.GetPointAssets(), globalAsset.GetBoxAssets());
            //UnityEngine.Object.Destroy(globalAsset);
        }
        
#if UNITY_EDITOR

        public interface IObjEditor
        {
        }
        public class SceneObjEditor : MonoBehaviour,IObjEditor
        {
            public MeshFilter meshFilter;
            public MeshRenderer meshRender;
            public Bounds aabb;
            public string assetName;
            
            public string belongScene;
            public SceneObj editorObj;
            public SceneBox.AssetDetailType editorObjType;
            public List<SceneBox> editorBelongBoxes;
        }

        public class SceneObjDynamicEditor : MonoBehaviour, IObjEditor
        {
            public Bounds aabb;
            
            public string belongScene;
            public SceneObj editorObj;
            public SceneBox.AssetDetailType editorObjType;
            public List<SceneBox> editorBelongBoxes;
        }

        public static void ScanScenes(UnityEngine.SceneManagement.Scene[] allUnityScenes, int xz, int h)
        {
            List<Bounds> unitySceneBounds = new List<Bounds>(10000);
            Dictionary<UnityEngine.SceneManagement.Scene, Bounds> allSceneBounds =
                new Dictionary<UnityEngine.SceneManagement.Scene, Bounds>(100);
            float scanAverage = 1.0f / allUnityScenes.Length;
            float progress = scanAverage;
            foreach (var unityScene in allUnityScenes)
            {
                
                EditorUtility.DisplayProgressBar("Scan unity scene bounds", $"current scene is {unityScene.name}",
                    progress);
                progress += scanAverage;
                var allRootObjs = unityScene.GetRootGameObjects();
                List<Bounds> allBounds = new List<Bounds>();
               // var terrain = GetTerrain(unityScene, true);
               foreach (var rootObj in allRootObjs)
               {
                   //meshMat
                   var objs = rootObj.GetComponentsInChildren<MeshFilter>();
                   foreach (var mesh in objs)
                   {
                       var render = mesh.gameObject.GetComponent<MeshRenderer>();
                       if (render != null)
                       {
                           var meshAsset = mesh.sharedMesh.name;
                           var objEditor = mesh.gameObject.AddComponent<SceneObjEditor>();
                           objEditor.belongScene = unityScene.name;
                           objEditor.meshFilter = mesh;
                           objEditor.meshRender = render;
                           objEditor.aabb = render.bounds;
                           objEditor.assetName = $"{meshAsset}|{render.sharedMaterial.name}";
                           allBounds.Add(objEditor.aabb);
                           var result = SceneAssetPool.CollectAsset(mesh.sharedMesh, render.sharedMaterial);
                           objEditor.assetName = $"{result.Item1}|{result.Item2}";

                           mesh.mesh = null;
                           render.material = null;
                           render.sharedMaterial = null;
                       }
                   }

                   var notifies = rootObj.gameObject.GetComponentsInChildren<SceneObj.BaseDynamicObjAgent>();
                   foreach (var notify in notifies)
                   {
                       var objEditor = notify.gameObject.AddComponent<SceneObjDynamicEditor>();
                       notify.SetDefault();
                       objEditor.belongScene = unityScene.name;
                       objEditor.aabb = notify.GetBounds();
                   }
               }

               var sceneBounds =  SceneUtility.GetBounds(allBounds);
                //var sceneBounds = terrain.terrainData.bounds;
                allSceneBounds.Add(unityScene, sceneBounds);
                unitySceneBounds.Add(sceneBounds);
            }
            //标记完成

            var globalBound = SceneUtility.GetBounds(unitySceneBounds);
            Vector3 gs = globalBound.center - globalBound.extents;
            Vector3 ge = globalBound.center + globalBound.extents;
            var gg = globalBound.size;
            gs -= new Vector3(xz, h, xz) * 0.5f;
            var nx = (int)(gg.x / xz) + 1;
            var nz = (int)(gg.z / xz) + 1;
            //var ny = (int)(gg.y / h) + 1;
            var ny = 1;
            List<SceneBox> globalBoxes = new List<SceneBox>(10000);
            List<ScenePoint> globalPoints = new List<ScenePoint>(10000);
            scanAverage = 1.0f / ny;
            progress = scanAverage;
            for (int k = 0; k <= ny; k++) // y
            {
                for (int i = 0; i <= nz; i++) //z
                {
                    for (int j = 0; j <= nx; j++) //x
                    {
                        var pointCenter = new Vector3(j * xz, k * h, i * xz) + gs;
                        var scenePoint = new ScenePoint(pointCenter);
                        globalPoints.Add(scenePoint);
                        if (k < ny && i < nz && j < nx)
                        {
                            var id = (j + 1) + 1000 * (i + 1) + 1000000 * (k + 1);
                            var center = pointCenter + new Vector3(xz, h, xz) * 0.5f;
                            var box = new SceneBox(id, new Bounds(center, new Vector3(xz, h, xz)));
                            globalBoxes.Add(box);
                            //scenePoint.BoxIds.Add(box.BoxId);
                        }
                        
                        EditorUtility.DisplayProgressBar("build scene points",
                            $"current h level is {k}/{ny},{i}/{nz},{j}/{nx}", progress);
                    }
                }

                progress += scanAverage;
            }

            int progressAtIndex = 0;
            int totalProgressCount = globalPoints.Count;
            foreach (var point in globalPoints)
            {
                foreach (var box in globalBoxes)
                {
                    var overlap = SceneUtility.TestAABBOverlap(box.BoxBounds, point.PointBound);
                    if (overlap)
                    {
                        point.BoxIds.Add(box.BoxId);
                    }
                }
            
                EditorUtility.DisplayProgressBar("build scene points",
                    $"point at {progressAtIndex}/{totalProgressCount}/{globalBoxes.Count}", GetProgress());
                progressAtIndex++;
            }

            progressAtIndex = 0;
            totalProgressCount = globalBoxes.Count;
            foreach (var box in globalBoxes)
            {
                foreach (var sceneBound in allSceneBounds)
                {
                    var overlap = SceneUtility.TestAABBOverlap(box.BoxBounds, sceneBound.Value);
                    if (overlap)
                    {
                        box.MarkAtScene(sceneBound.Key.name);
                    }

                    EditorUtility.DisplayProgressBar("fill box scene info ",
                        $"scene bound at {progressAtIndex}/{totalProgressCount}/{allSceneBounds.Count}", GetProgress());
                }

                progressAtIndex++;
            }
            //构建所有box和point

            progressAtIndex = 0;
            totalProgressCount = allUnityScenes.Length;
            List<SceneBox> tmp = new List<SceneBox>(1000);
            Dictionary<UnityEngine.SceneManagement.Scene, Tuple<List<SceneObjEditor>, List<SceneObjDynamicEditor>>>
                allSceneEditorObjs =
                    new Dictionary<UnityEngine.SceneManagement.Scene,
                        Tuple<List<SceneObjEditor>, List<SceneObjDynamicEditor>>>(100);
            foreach (var unityScene in allUnityScenes)
            {
                var allRootObjs = unityScene.GetRootGameObjects();
                
                Tuple<List<SceneObjEditor>, List<SceneObjDynamicEditor>> item =
                    new Tuple<List<SceneObjEditor>, List<SceneObjDynamicEditor>>(new List<SceneObjEditor>(),new List<SceneObjDynamicEditor>());
                allSceneEditorObjs.Add(unityScene,item);
                foreach (var rootObj in allRootObjs)
                {
                    var objs = rootObj.GetComponentsInChildren<SceneObjEditor>();
                    foreach (var eObj in objs)
                    {
                        var assetType = SceneUtility.ToAssetType(eObj);
                        var so = new MeshMatData(eObj.aabb, assetType, eObj.assetName, eObj.transform, eObj.meshFilter,
                            eObj.meshRender);
                        eObj.editorObj = so;
                        eObj.editorObjType = assetType;

                        var belongBoxes = GetBelongSceneBox(so, eObj.belongScene);
                        if (belongBoxes != null && belongBoxes.Count != 0)
                        {
                            eObj.editorBelongBoxes = new List<SceneBox>(belongBoxes.Count);
                            eObj.editorBelongBoxes.AddRange(belongBoxes.ToArray());

                            foreach (var odBox in belongBoxes)
                            {
                                var loading = odBox.sceneObjMap[assetType];
                                loading.Objs.Add(so);
                            }

                            item.Item1.Add(eObj);

                            UnityEngine.Object.DestroyImmediate(eObj);
                        }
                    }

                    var notifies = rootObj.GetComponentsInChildren<SceneObjDynamicEditor>();
                    foreach (var not in notifies)
                    {
                        var assetType = SceneUtility.ToAssetType(not);
                        var so = new DynamicObjData(not.aabb, assetType, not.gameObject);
                        not.editorObj = so;
                        not.editorObjType = assetType;
                        
                        var belongBoxes = GetBelongSceneBox(so, not.belongScene);
                        if (belongBoxes != null && belongBoxes.Count != 0)
                        {
                            not.editorBelongBoxes = new List<SceneBox>(belongBoxes.Count);
                            not.editorBelongBoxes.AddRange(belongBoxes.ToArray());

                            foreach (var odBox in belongBoxes)
                            {
                                var loading = odBox.sceneObjMap[assetType];
                                loading.Objs.Add(so);
                            }

                            item.Item2.Add(not);

                            UnityEngine.Object.DestroyImmediate(not);
                        }
                    }

                    EditorUtility.DisplayProgressBar("fill scene obj info ",
                        $"scene bound at {progressAtIndex}/{totalProgressCount}/{objs.Length}", GetProgress());
                }
                progressAtIndex++;
                
                
            }

            Dictionary<UnityEngine.SceneManagement.Scene, List<SceneAssets.SceneObjWrap>> unitySceneObjs =
                new Dictionary<UnityEngine.SceneManagement.Scene, List<SceneAssets.SceneObjWrap>>();
            progressAtIndex = 0;
            totalProgressCount = allSceneEditorObjs.Count;
            foreach (var editorObj in allSceneEditorObjs)
            {
                List<SceneAssets.SceneObjWrap> wrapList = new List<SceneAssets.SceneObjWrap>();
                foreach (var item in editorObj.Value.Item1)
                {
                    var wrap = new SceneAssets.SceneObjWrap();
                    wrapList.Add(wrap);
                    wrap.obj = item.editorObj;
                    wrap.detailType = item.editorObjType;
                    wrap.belongBoxes = new List<SceneBox>();
                    wrap.belongBoxes.AddRange(item.editorBelongBoxes);
                }

                foreach (var item in editorObj.Value.Item2)
                {
                    var wrap = new SceneAssets.SceneObjWrap();
                    wrapList.Add(wrap);
                    wrap.obj = item.editorObj;
                    wrap.detailType = item.editorObjType;
                    wrap.belongBoxes = new List<SceneBox>();
                    wrap.belongBoxes.AddRange(item.editorBelongBoxes);
                }
                EditorUtility.DisplayProgressBar("fill scene wrapObj info ",
                    $"scene bound at {progressAtIndex}/{totalProgressCount}", GetProgress());
                unitySceneObjs.Add(editorObj.Key,wrapList);
            }
            //建立场景对象信息
            
            foreach (var gb in globalBoxes)
            {
                var n = 0;
                foreach (var item in gb.sceneObjMap)
                {
                    n = item.Value.Objs.Count;
                }
                Debug.Log($"scene box info,total assets = {n},box id = {gb.BoxId}");
            }
            //数据自检

            progressAtIndex = 0;
            totalProgressCount = unitySceneObjs.Count;
            foreach (var kvp in unitySceneObjs)
            {
                var sa = new GameObject("_se_").AddComponent<SceneAssets>();
                sa.EditorAdd(kvp.Value,allSceneBounds[kvp.Key]);
                UnityEngine.SceneManagement.SceneManager.MoveGameObjectToScene(sa.gameObject, kvp.Key);
                EditorUtility.SetDirty(sa);

                UnityEditor.SceneManagement.EditorSceneManager.SaveScene(kvp.Key,
                    $"Assets/TestScene/AutoGen/{kvp.Key.name}.unity");

                EditorUtility.DisplayProgressBar("save scene obj info ",
                    $"save scene at {progressAtIndex}/{totalProgressCount}", GetProgress());
                progressAtIndex++;
            }
            //场景对象信息保存

            var gscene = EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Additive);
            var g = new GameObject("_global_").AddComponent<GlobalAssets>();
            g.EditorAdd(globalBound, globalPoints, globalBoxes);
            UnityEngine.SceneManagement.SceneManager.MoveGameObjectToScene(g.gameObject, gscene);

            UnityEditor.SceneManagement.EditorSceneManager.SaveScene(gscene,
                $"Assets/TestScene/AutoGen/_GLOBAL.unity");
            
            SceneAssetPool.MoveAssets();

            EditorUtility.ClearProgressBar();
            Debug.Log("scan finish!");
            //全局信息保存

            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            List<SceneBox> GetBelongSceneBox(SceneObj obj, string scene)
            {
                tmp.Clear();

                foreach (var box in globalBoxes)
                {
                    if (!box.BeScene.Contains(scene))
                        continue;
                    var overlap = SceneUtility.TestAABBOverlap(box.BoxBounds, obj.objBounds);
                    if (overlap == false)
                        continue;
                    tmp.Add(box);
                }

                return tmp;
            }

            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            float GetProgress()
            {
                return Mathf.InverseLerp(0, totalProgressCount, progressAtIndex);
            }
            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            
            Terrain GetTerrain(UnityEngine.SceneManagement.Scene scene,bool check = true)
            {
                var rootObjs = scene.GetRootGameObjects();
                Terrain t = null;
                foreach (var obj in rootObjs)
                {
                    var terrains = obj.GetComponentsInChildren<Terrain>();
                    if (terrains != null)
                    {
                        if (check && t != null)
                            throw new Exception("scene terrain exception");
                        t = terrains[0];
                        if (check == false)
                            return t;
                    }
                }

                return t;
            }
        }

        [MenuItem("Tools/LoadTest")]
        static void TestWindow()
        {
            string[] scenes = new string[]
            {
                "Assets/TestScene/TestEditor/New Scene 1.unity",
                "Assets/TestScene/TestEditor/New Scene 2.unity",
                "Assets/TestScene/TestEditor/New Scene 3.unity",
                "Assets/TestScene/TestEditor/New Scene 4.unity",
                "Assets/TestScene/TestEditor/New Scene 5.unity",
                "Assets/TestScene/TestEditor/New Scene 6.unity",
                "Assets/TestScene/TestEditor/New Scene 7.unity",
                "Assets/TestScene/TestEditor/New Scene 8.unity",
            };
            List<UnityEngine.SceneManagement.Scene> list = new List<UnityEngine.SceneManagement.Scene>();
            bool flag = false;
            foreach (var scene in scenes)
            {
                var s = UnityEditor.SceneManagement.EditorSceneManager.OpenScene(scene,
                    flag == false ? OpenSceneMode.Single : OpenSceneMode.Additive);
                flag = true;
                //list.Add(UnityEngine.SceneManagement.SceneManager.GetSceneByName(scene.Substring(scene.LastIndexOf('/')+1)));
                list.Add(s);
            }

            ScanScenes(list.ToArray(), 500, 500);
        }

        [MenuItem("Tools/LoadTest2")]
        static void Test2()
        {
            string[] scenes = new string[]
            {
                "Assets/TestScene/TestEditor/New Scene 1.unity",
                "Assets/TestScene/TestEditor/New Scene 2.unity",
                "Assets/TestScene/TestEditor/New Scene 3.unity",
                "Assets/TestScene/TestEditor/New Scene 4.unity",
                "Assets/TestScene/TestEditor/New Scene 5.unity",
                "Assets/TestScene/TestEditor/New Scene 6.unity",
                "Assets/TestScene/TestEditor/New Scene 7.unity",
                "Assets/TestScene/TestEditor/New Scene 8.unity",
            };
            List<UnityEngine.SceneManagement.Scene> list = new List<UnityEngine.SceneManagement.Scene>();
            bool flag = false;
            foreach (var scene in scenes)
            {
                var s = UnityEditor.SceneManagement.EditorSceneManager.OpenScene(scene,
                    flag == false ? OpenSceneMode.Single : OpenSceneMode.Additive);
                flag = true;
                list.Add(s);
            }
        }
#endif
    }

    public static class SceneUtility
    {
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static bool TestAABBOverlap(Bounds a, Bounds b)
        {
            if (a.Intersects(b))
                return true;
            if (a.Contains(b.center))
                return true;
            if (b.Contains(a.center))
                return true;
            return false;
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static bool TestAABBOverlap(Bounds a, Vector3 point)
        {
            return a.Contains(point);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static Bounds GetBounds(List<Bounds> allBounds)
        {
            var bounds = allBounds[0];
            if (allBounds.Count == 1)
                return bounds;
            foreach (Bounds b in allBounds)
            {
                // 合并所有的边界
                bounds.Encapsulate(b);
            }

            return bounds;
        }
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static bool SceneObjCheckRemove(SceneBox box, SceneBox.AssetDetailType detailType, SceneObj obj)
        {
            if (obj.IsReleased)
            {
                if (box.sceneObjMap.TryGetValue(detailType, out var state))
                {
                    state.Objs.RemoveFast(obj);
                    SceneUtility.LogInfo($"Remove scene obj from box {box.BoxId}, type is {detailType}");
                }

                return true;
            }

            return false;
        }

        public static Bounds GetBounds(this SceneObj.IObj dynamicObj)
        {
            if (dynamicObj is SceneObj.BaseDynamicObjAgent obj)
            {
                var renders = obj.gameObject.GetComponentsInChildren<MeshRenderer>();
                List<Bounds> bounds = new List<Bounds>();
                foreach (var item in renders)
                {
                    bounds.Add(item.bounds);
                }

                return SceneUtility.GetBounds(bounds);
            }

            throw new NotImplementedException("GetBounds error");
        }

#if UNITY_EDITOR
        public static SceneBox.AssetDetailType ToAssetType(SceneBox.IObjEditor objEditor)
        {
            if (objEditor is SceneBox.SceneObjEditor meshMat)
            {
                var assetSize = meshMat.aabb.size;
                if (assetSize.x > 100 || assetSize.y > 100 || assetSize.z > 100)
                    return SceneBox.AssetDetailType.Important;
                if (assetSize.x > 70 || assetSize.y > 70 || assetSize.z > 70)
                    return SceneBox.AssetDetailType.Detail1;
                if (assetSize.x > 40 || assetSize.y > 40 || assetSize.z > 40)
                    return SceneBox.AssetDetailType.Detail2;
                return SceneBox.AssetDetailType.Detail3;
            }

            if (objEditor is SceneBox.SceneObjDynamicEditor notify)
            {
                return SceneBox.AssetDetailType.DynamicType;
            }

            throw new Exception("ToAssetType unknow");
        }
#endif

        public static void LogInfo(string info)
        {
            //UnityEngine.Debug.Log(info);
        }

        public static void LogError(string info)
        {
            UnityEngine.Debug.LogError(info);
        }
    }
    
    public static class GameUtility
    {
        public static void RemoveFast<T>(this List<T> list, T obj) where T : class
        {
            for (int i = 0; i < list.Count; i++)
            {
                if (object.ReferenceEquals(list[i], obj))
                {
                    var last = list.Count - 1;
                    if (i < last) list[i] = list[last];
                    list.RemoveAt(last);
                    break;
                }
            }
        }
        public static void RemoveFast<T>(this List<T> list, int idx) //where T : class
        {
            var last = list.Count - 1;
            if (idx < last) list[idx] = list[last];
            list.RemoveAt(last);
        }
    }
}